package xyz.zyt123.hikvideo.filter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.zyt123.hikvideo.bean.User;
import xyz.zyt123.hikvideo.common.AjaxResult;
import xyz.zyt123.hikvideo.util.JsonUtil;
import xyz.zyt123.hikvideo.util.JwtUtil;

import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

@WebFilter
public class JwtAuthenticationFilter implements Filter {
  private static final Set<String> ignoreUrls = new HashSet<>();
  private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

  static {
    ignoreUrls.add("/api/v1/device/cameras");
    ignoreUrls.add("/api/v1/user/login");
    ignoreUrls.add("/api/v1/user/register");
  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpSession httpSession = request.getSession();
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    log.info("filter:{}", request.getRequestURI());
    String jwt = request.getHeader("authorization");
    // 这里如果没有jwt，继续往后走，因为后面还有鉴权管理器等去判断是否拥有身份凭证，所以是可以放行的
    // 没有jwt相当于匿名访问，若有一些接口是需要权限的，则不能访问这些接口
    if (ignoreUrls.contains(request.getRequestURI())
        || request.getRequestURI().startsWith("/api/live/")
        || request.getRequestURI().startsWith("/api/image/")
        || request.getRequestURI().startsWith("/api/video/")) {
      chain.doFilter(request, response);
      return;
    }
    if (StringUtils.isBlank(jwt)) {
      response.setStatus(401);
      response.getWriter().write(JsonUtil.objectToJson(AjaxResult.authentication("登录已过期")));
      return;
    }
    Claims claim;
    try {
      claim = JwtUtil.parseJWT(jwt.split(" ")[1]);
    } catch (ExpiredJwtException expiredJwtException) {
      response.setStatus(401);
      response.getWriter().write(JsonUtil.objectToJson(AjaxResult.authentication("登录已过期")));
      return;
    }
    if (claim == null) {
      response.setStatus(401);
      response.getWriter().write(JsonUtil.objectToJson(AjaxResult.authentication("登录已过期")));
      return;
    }
    if (claim.getExpiration().before(DateUtils.addMinutes(new Date(), -5))) {
      response.setHeader("refresh-token", JwtUtil.createJWT(claim.getSubject()));
    }
    User user = JsonUtil.jsonToObject(claim.getSubject(), User.class);
    if (user == null) {
      response.setStatus(401);
      response.getWriter().write(JsonUtil.objectToJson(AjaxResult.authentication("登录已过期")));
      return;
    }
    httpSession.setAttribute("user", user);
    chain.doFilter(request, response);
    httpSession.removeAttribute("user");
  }
}
